////////////////////////////////////////////////////////////////////////////////
// Подключение файлов
#include <tadbg.h>
#include <res_def.h>
#include <DAL.h>
#include <mem.h>

#include "elf.h"

#include "bmp.h"
#include "misc.h"

#include "gdi.h"
#include "kbd.h"
#include "font.h"
#include "dlghack.h"
//#include <.h>
//#include ".h"





////////////////////////////////////////////////////////////////////////////////
// Описание структур

typedef struct
{
	BOOL	up;
	BOOL	down;
	BOOL	left;
	BOOL	right;
	BOOL	fire;
	BOOL    lsoft;
	BOOL    rsoft;
} KEYS_T;

typedef struct
{
	INT32	width;
	INT32	height;
	UINT8	reserved1;
	void*	data;
} LEVEL_T;






////////////////////////////////////////////////////////////////////////////////
// Описание функций

static	UINT32	AppStart(EVENT_STACK_T* ev_st, REG_ID_T reg_id, UINT32 param2);
static	UINT32	AppExit(EVENT_STACK_T* ev_st, APPLICATION_T* app);

static	UINT32	FreeResources(void);
static	UINT32	InitResources(void);

static	UINT32	HandleUITokenGranted(EVENT_STACK_T* ev_st,  APPLICATION_T * app );

static	UINT32	MainStateEnter(EVENT_STACK_T* ev_st, APPLICATION_T* app, ENTER_STATE_TYPE_T type);
static	UINT32	MainStateExit(EVENT_STACK_T* ev_st, APPLICATION_T* app, EXIT_STATE_TYPE_T type);

static	UINT32	HandleKeyPress(EVENT_STACK_T* ev_st, APPLICATION_T* app);
static	UINT32	HandleKeyRelease(EVENT_STACK_T* ev_st, APPLICATION_T* app);
static	UINT32	HandleExit(EVENT_STACK_T* ev_st, APPLICATION_T* app);
static	UINT32	HandleTimerExpiried(EVENT_STACK_T* ev_st, APPLICATION_T* app);
//static	UINT32	Handle(EVENT_STACK_T* ev_st, APPLICATION_T* app);

static	void	displayCbk(const RECT_T* updatedRect);

static	UINT32	RenderSoftKeysAndHeader(BOOL lS, BOOL rS);
static	UINT32	RenderMenu( void );

static	void	keyboardCbk(APPLICATION_T* app, KEY_DATA_T* key);

static	BOOL	Lose( void );
static	BOOL	Won( void );
static	BOOL	Mov(INT8 X, INT8 Y);
static	void	NewGame(INT8 nLevel);
static	void	Physics( void );
static	void	Render( void );

static	UINT8	LvlGetData(INT32 dwX, INT32 dwY);
static	UINT8	LvlSetData(INT32 dwX, INT32 dwY, UINT8 data);

static	void	Menu_PrevItem(void);
static	void	Menu_NextItem(void);
static	void	Menu_BackItem(void);
static	void	Menu_SelectItem(void);






////////////////////////////////////////////////////////////////////////////////
// Описание констант
#define NULL_DLG

#define	TIMER_ID		0xDEF1D
#define	TIMER_TIMEOUT	50

#define	ELF_NAME		"Kosilka"

#define MAX_SZ_SIZE		255

#define SIZE			10

#define SQSIZE			16

#define FLEFT			(DISPLAY_WIDTH-SQSIZE*SIZE)/2
#define FTOP			(DISPLAY_HEIGHT-SQSIZE*SIZE)/2

#define g 1
#define b 2
#define c 3

#define ST_INACTIVE		0x0
#define ST_MENU			0x1
#define ST_PLAYING		0x8
#define ST_COMPLETED	0x10
#define	ST_GAMEOVER		0x80
#define ST_EXITING		0x100
#define ST_EXIT			0x200

#define DRAW_HEAD		0x1
#define DRAW_LEFTS		0x2
#define DRAW_RIGHTS		0x4





////////////////////////////////////////////////////////////////////////////////
// Описание глобальных основных переменных

// Название приложения. Длина строки именно такая и никакая иначе
const char	app_name[APP_NAME_LEN] = ELF_NAME;

// Путь к папке в которой лежит приложение. Без слеша в конце.
WCHAR		workdir[FS_MAX_URI_NAME_LENGTH+1];

// Структура, которая идентифицирует приложение.
//APP_T*		zapp;

UINT32		evcode_base;
ldrElf		elf;





////////////////////////////////////////////////////////////////////////////////
// Описание глобальных переменных
RECT_T		cbkRect = {0, 0, 176, 220};

UINT32		hTimer;

AHIDEVCONTEXT_T	hDC;
AHISURFACE_T	hDisp, hDraw;

UINT32			state = ST_INACTIVE;
UINT32			pkey = NULL;

UINT32			menusel = 0;

//AHIBITMAP_T	bitmap;

KEYS_T			keys = {false, false, false, false, false, false, false};

LEVEL_T			lvl = {10, 10, NULL};

//APPLICATION_T	game;

INT8		    level, lastlevel;

AHIPOINT_T	    pos = {0, 0};
AHIPOINT_T      kospos, newpos;

ANIMATION_T	    kos, tiles[3];
BOOL		    res = false;

//INT8		    item = 1;
INT8		    side = 0;

UINT32		    clTrans = ATI_565RGB(255, 0, 255), clActive = ATI_565RGB(255, 255, 255), clNormal = ATI_565RGB(210, 210, 210);
UINT32		    clBackNormal = ATI_565RGB(69, 69, 69), clBackActive = ATI_565RGB(128, 128, 128);

BOOL            moving = false;

//AHIBITMAP_T	bitmap;





////////////////////////////////////////////////////////////////////////////////
// Обработчики событий для каждого state-а

// Обработчики событий для APP_STATE_ANY (используется в любом state)
static EVENT_HANDLER_ENTRY_T any_state_handlers[] =
{
	{ EV_REVOKE_TOKEN,		APP_HandleUITokenRevoked	},
	{ EV_PM_API_EXIT,		HandleExit					},		// PM API: cmd EXIT

	// Список всегда должен заканчиватся такой записью
	{ STATE_HANDLERS_END,	NULL						}
};

static EVENT_HANDLER_ENTRY_T init_state_handlers[] =
{
	{ EV_GRANT_TOKEN,		HandleUITokenGranted		},		// Обработка Token'ов

	// Список всегда должен заканчиватся такой записью
	{ STATE_HANDLERS_END,	NULL						}
};

static EVENT_HANDLER_ENTRY_T main_state_handlers[] =
{
#ifndef WIN32
	#ifndef NULL_DLG
	{ EV_INK_KEY_PRESS,		HandleKeyPress				},		// Нажатие кнопки
	{ EV_INK_KEY_RELEASE,	HandleKeyRelease			},		// Отжатие кнопки
	#endif
#else
	#ifndef NULL_DLG
	{ EV_KEY_PRESS,			HandleKeyPress				},		// Нажатие кнопки в EmuElf
	{ EV_KEY_RELEASE,		HandleKeyRelease			},		// Отжатие кнопки в EmuElf
	#endif
#endif
	{ EV_TIMER_EXPIRED,		HandleTimerExpiried 		},		// Срабатывание таймера

	// Список всегда должен заканчиватся такой записью
	{ STATE_HANDLERS_END,	NULL						}
};





////////////////////////////////////////////////////////////////////////////////
// Таблица соответствий обработчиков, состояний и функций входа-выхода из состояния.
// Порядок состояний такой же, как в enum-e

static const STATE_HANDLERS_ENTRY_T state_handling_table[] =
{
	{ APP_STATE_ANY,		// State
		NULL,				// Обработчик входа в state
		NULL,				// Обработчик выхода из state
		any_state_handlers	// Список обработчиков событий
	},

	{ APP_STATE_INIT,
		NULL,
		NULL,
		init_state_handlers
	},

	{ APP_STATE_MAIN,
		MainStateEnter,		// NULL,
		MainStateExit,		// NULL,
		main_state_handlers
	}
};





////////////////////////////////////////////////////////////////////////////////
// Это EntryPoint для всех эльфов, должна быть объявлена именно так
// uri - путь к эльфу (аналогично argv[0])
// params - параметры эльфа (аналогично остальным argv)
ldrElf*	_start(WCHAR* uri, WCHAR* params) {
	UINT32				reserve, status = RESULT_OK;
	UINT8				i;

	// Чтоб компилер не ругался
	uri = uri;
	params = params;

	dbg("_start: Enter");

	// Проверяем, а вдруг уже запущено?
	if (ldrIsLoaded((char*)app_name)) {
		cprint("\x87" ELF_NAME ":\x8c Already Loaded!\n");
		return NULL; // Нам не нужен второй экземпляр
	}

	evcode_base = ldrRequestEventBase();
	elf.evbase = evcode_base;

	// инитим таблицы ивентов
	reserve = evcode_base + 1;
	for (i = 0; i < sizeof(state_handling_table)/sizeof(STATE_HANDLERS_ENTRY_T); i++ ) {
		reserve = ldrInitEventHandlersTbl((EVENT_HANDLER_ENTRY_T *)state_handling_table[i].htable, reserve);
	}

	// Регистрируем приложение
	status = APP_Register(	&evcode_base,			// На какое событие должно запускаться приложение
							1,						// Кол-во событий, на которое должно запускаться приложение
							state_handling_table,	// Таблица состояний
							APP_STATE_MAX,			// Количество состояний
							(void*)AppStart );		// Функция, вызываемая при запуске

	dbgf("_start: APP_Register, status = %d", status);

	// Сохраняем путь к папке, в которой лежит приложение
	w_mkdir(workdir, uri);

	elf.name = (char*)app_name;
	ldrSendEvent(evcode_base); // Запустить немедленно

	dbg("_start: Exit");

	return &elf;
}





// Функция вызываемая при старте приложения
UINT32	AppStart(EVENT_STACK_T* ev_st,  REG_ID_T reg_id,  UINT32 param2) {

	APP_T				*app = NULL;
	UINT32				status = RESULT_OK;

	dbg("AppStart: Enter");

	// Инициализация для фоновых приложений
	app = (APP_T*) APP_InitAppData(	(void*)APP_HandleEvent,			// Обработчик для фоновых приложений. В режиме велосипеда, оказывается, глюки с UIS
									sizeof(APP_T),					// Размер структуры приложения
									reg_id,
									0, 0,
									1,
									AFW_APP_CENTRICITY_PRIMARY,
									AFW_FOCUS,
									AFW_POSITION_TOP );

	dbgf("AppStart: APP_InitAppData, app = 0x%X", app);

	if ( !app )	{
		cprint("\x87" ELF_NAME ":\x8c Init Failed!\n");
		return ldrUnloadElf();
	}

	elf.app = (APPLICATION_T*)app;

	// Сохраним app для дальнейших манипуляций
	//zapp = app;

	app->iface.port = app->apt.port;
	app->iface.handle = NULL;

	app->port = app->apt.port;
	app->key_ind = 0;
	app->sleep = TIMER_TIMEOUT;

	status = APP_Start( ev_st, (APPLICATION_T*)app,
						APP_STATE_INIT,								// Начальное состояние для приложения
						state_handling_table,
						AppExit,
						app_name,
						0 );

	dbgf("AppStart: APP_Start, status = 0x%X", status);

	if ( status == RESULT_OK ) {
		elf.app = (APPLICATION_T*)app;
		status = InitResources();									// Загрузка ресурсов
		if (status != RESULT_OK) {									// А если они не загрузились...
			cprint("\x87" ELF_NAME ":\x8c Init Res Failed!\n");		// Выдаём сообщение и вырубаемся
			APP_HandleFailedAppStart(ev_st, elf.app, 0);
			return ldrUnloadElf();
		}
		GDI_Init(&hDC, &hDisp, &hDraw, app_name, app, GDI_PRIVATEDC, AHIROP_PATCOPY, AHIROP_PATCOPY, false);	// Инициализация драйвера
        KBD_Init(app);                                                                                          // Инициализация клавиатурной подсистемы
//		ldrDisplayCbkReg((dispCbk)displayCbk, &cbkRect, TRUE);													// Регистрация коллбека
		hTimer = TimerInit(TIMER_TIMEOUT, TIMER_ID, tttCyclical, app);  										// Старт таймера
	} else {
		cprint("\x87" ELF_NAME ":\x8c Start Failed!\n");
		APP_HandleFailedAppStart(ev_st, elf.app, 0);
		return ldrUnloadElf();
	}

	dbg("AppStart: Exit");

	return RESULT_OK;
}





// Функция выхода из приложения
UINT32	AppExit( EVENT_STACK_T* ev_st,  APPLICATION_T* app ) {

	UINT32				status;

	dbg("AppExit: Enter");

	TimerDel(&hTimer, app);						// Остановка таймера
//	ldrDisplayCbkUnReg((dispCbk)displayCbk);	// Удаление коллбека
    KBD_UnInit();
	GDI_UnInit(&hDC);							// Деинициализация драйвера
	FreeResources();							// Очистка от загруженных ресурсов

	dbg("AppExit: Exit");

	// Завершаем работу приложения
	status = APP_ExitStateAndApp(ev_st, app, 0);

	// Выгружаем эльф
	return ldrUnloadElf();
}





// Функция для загрузки ресурсов
UINT32	InitResources( void ) {
	WCHAR			save_url[MAX_SZ_SIZE+1];
	FILE_HANDLE_T	savefile;
	UINT32			readen;
	UINT8           i;

	WCHAR			bmp_url[MAX_SZ_SIZE+1];
	BOOL			result = true;

	dbg("InitResources: Enter");

	u_strncpy(save_url, workdir, MAX_SZ_SIZE);
	u_strcat(save_url, L"/Kosilka.res/savegame.dat");
	savefile = DL_FsOpenFile(save_url, FILE_READ_MODE, 0);
	if (savefile != FILE_HANDLE_INVALID) {
		DL_FsReadFile(&level, sizeof(INT8), 1, savefile, &readen);
		DL_FsCloseFile(savefile);
	} else {
		level = 1;
	}
	lastlevel = level;

	u_strncpy(bmp_url, workdir, MAX_SZ_SIZE);
	u_strcat(bmp_url, L"/Kosilka.res/images/kos.bmp");
	if (GDI_LoadAniBitmap(&kos, bmp_url) != RESULT_OK) { result = false; } else { kos.active = false; }

	for (i = 0; i <= 2; i++) {
		u_strncpy(bmp_url, workdir, FS_MAX_URI_NAME_LENGTH);
		switch (i) {
			case 0:
				u_strcat(bmp_url, L"/Kosilka.res/images/seno.bmp");
				break;
			case 1:
				u_strcat(bmp_url, L"/Kosilka.res/images/block.bmp");
				break;
			case 2:
				u_strcat(bmp_url, L"/Kosilka.res/images/grnd.bmp");
				break;
		}
		if (GDI_LoadAniBitmap(&tiles[i], bmp_url) != RESULT_OK) { result = false; }
	}

	res = result;

	dbg("InitResources: Exit");

	return RESULT_OK;
}





// Функция для выгрузки ресурсов
UINT32	FreeResources( void ) {
	WCHAR			save_url[MAX_SZ_SIZE+1];
	FILE_HANDLE_T	savefile;
	UINT32			written;
	UINT8           i;

	dbg("FreeResources: Enter");

	GDI_UnLoadAniBitmap(&kos);

	for (i = 0; i <= 2; i++) { GDI_UnLoadAniBitmap(&tiles[i]); }

	u_strncpy(save_url, workdir, MAX_SZ_SIZE);
	u_strcat(save_url, L"/Kosilka.res/savegame.dat");
	savefile = DL_FsOpenFile(save_url, FILE_WRITE_MODE, 0);
	if (savefile != FILE_HANDLE_INVALID) {
		DL_FsWriteFile(&lastlevel, sizeof(INT8), 1, savefile, &written);
		DL_FsCloseFile(savefile);
	}

	dbg("FreeResources: Exit");

	return RESULT_OK;
}





// Обработчыик входа в MainState
UINT32	MainStateEnter(EVENT_STACK_T* ev_st, APPLICATION_T* app, ENTER_STATE_TYPE_T type) {
	// Получаем структуру приложения
	APP_T					*papp = GetAPP(app);
#ifndef NULL_DLG
	// Размеры Canvas'а. Для "пустого" диалога не нужен.
	DRAWING_BUFFER_T		bufd = {NULL, 176, 220};
#endif

	if ( type != ENTER_STATE_ENTER ) {
		return RESULT_OK;
	}

	dbg("MainStateEnter: Enter");

#ifndef WIN32
	// Отключаем статус-строку... Только если у нас не EmuElf!
	setCanvasControl__13StatusManagerFScPUs(&theStatusManager, TRUE, NULL);
#endif

#ifdef NULL_DLG
	// Создаем "пустой" диалог.
	papp->dialog = UIS_CreateNullDialog(&papp->port);
#else
	// Создаем Canvas. Если предыдущий вариант не подошёл...
	papp->dialog = UIS_CreateColorCanvas(&papp->port, &bufd, TRUE);
#endif

	dbgf("MainStateEnter: dialog = 0x%08x", papp->dialog);

	if (papp->dialog == NULL) {
		return RESULT_FAIL;
	}

	papp->apt.dialog = papp->dialog;
	// papp->sleep = TIMER_TIMEOUT;

	// Установка хука на клавиатуру
	KBD_AddHook((KEYHOOK_FUNC)keyboardCbk, MULTIKEY_ANY);

	NewGame(level);

	dbg("MainStateEnter: Exit");

	return RESULT_OK;
}





UINT32	MainStateExit(EVENT_STACK_T* ev_st, APPLICATION_T* app, EXIT_STATE_TYPE_T type) {
	// Получаем структуру приложения
	APP_T					*papp = GetAPP(app);

	dbg("MainStateExit: Enter");

	if (type != EXIT_STATE_EXIT) {
		return RESULT_OK;
	}

	if ( papp->apt.dialog != NULL ) {
		APP_UtilUISDialogDelete( &papp->apt.dialog );
	}

	dbg("MainStateExit: Exit");

	return RESULT_OK;
}





// Обработчик Token'ов
UINT32	HandleUITokenGranted(EVENT_STACK_T* ev_st,  APPLICATION_T* app) {
	// Получаем структуру приложения
	APP_T					*papp = GetAPP(app);
	UINT32					status;

	dbg("HandleUITokenGranted: Enter");

	// Вызываем дефолтный обработчик события
	status = APP_HandleUITokenGranted( ev_st, app );
	dbgf("HandleUITokenGranted: APP_HandleUITokenGranted DONE, status = %d", status);

	// Если всё хорошо, меняем текущий state
	if ((status == RESULT_OK) && (papp->apt.token_status == 2)) {
		status = APP_UtilChangeState( APP_STATE_MAIN, ev_st, app );
	}

	dbgf("HandleUITokenGranted: Exit, status=%d", status);

	return status;
}





// Обработчик нажатия на кнопку
UINT32	HandleKeyPress( EVENT_STACK_T* ev_st,  APPLICATION_T* app ) {
	// Получаем код кнопки
	UINT8	key = GET_KEY(ev_st);

	dbgf("HandleKeyPress: Enter, key = 0x%X", key);

	// Делаем что-нибудь
	/*
	switch (key) {
		case KEY_UP:
		case KEY_2:
			if (playing) {
			    if (!moving) {
			        moving = true;
                    side = 2;
                    Mov(pos.x, pos.y-1);
			    }
			} else {
				if (item > 1) { item--; } else { item = 4; }
				Render();
			}
			break;
		case KEY_DOWN:
		case KEY_8:
			if (playing) {
			    if (!moving) {
			        moving = true;
                    side = 0;
                    Mov(pos.x, pos.y+1);
			    }
			} else {
				if (item < 4) { item++; } else { item = 1; }
				Render();
			}
			break;
		case KEY_LEFT:
		case KEY_4:
			if (playing) {
			    if (!moving) {
			        moving = true;
			        side = 3;
			        Mov(pos.x-1, pos.y);
			    }
			}
			break;
		case KEY_RIGHT:
		case KEY_6:
			if (playing) {
			    if (!moving) {
			        moving = true;
                    side = 1;
                    Mov(pos.x+1, pos.y);
			    }
			}
			break;
		case KEY_SOFT_LEFT:
			RenderSoftKeysAndHeader(true, false);
			break;
		case KEY_SOFT_RIGHT:
			RenderSoftKeysAndHeader(false, true);
			break;
	}
	*/

	APP_ConsumeEv(ev_st, app);

	dbg("HandleKeyPress: Exit");

	return RESULT_OK;
}





// Обработчик отпускания кнопки
UINT32	HandleKeyRelease(EVENT_STACK_T* ev_st,  APPLICATION_T* app) {
	// Получаем код кнопки
	UINT8	key = GET_KEY(ev_st);

	dbgf("HandleKeyRelease: Enter, key = 0x%X", key);

	// Делаем что-нибудь
	/*
	switch (key) {
		case KEY_SOFT_LEFT:
			if (playing) { playing = false; } else { app->exit_status = TRUE; }
			RenderSoftKeysAndHeader(false, false);
			Render();
			break;
		case KEY_JOY_OK:
		case KEY_5:
			if (playing) {
				break;
			}
		case KEY_SOFT_RIGHT:
			if (playing) { NewGame(level); } else {
				switch (item) {
					case 1:
						playing = true;
						break;
					case 2:
						if ((level < lastlevel)) { level++; }
						NewGame(level);
						break;
					case 3:
						if (level > 1) { level--; }
						NewGame(level);
						break;
					case 4:
						app->exit_status = TRUE;
						break;
				}
			}
			RenderSoftKeysAndHeader(false, false);
			Render();
			break;
	}
	*/

	APP_ConsumeEv(ev_st, app);

	dbg("HandleKeyRelease: Exit");

	return RESULT_OK;
}





// Функция обработки события таймера
UINT32	HandleTimerExpiried(EVENT_STACK_T* ev_st, APPLICATION_T* app) {
	// Получаем идентификатор таймера
	UINT32	tid = GET_TIMER_ID(ev_st);

	switch (tid) {
		case GDI_TIMER:
			// Таймер требуется для работы GDI_EndPaintWithEffect. Не удалять!
			GDI_DrawEffect(&hDC);
			APP_ConsumeEv(ev_st, app);
			break;
		case KBD_TIMER:
			KBD_ProcessKeys();
			break;
		case TIMER_ID:
            newpos.x = FLEFT+pos.x*SQSIZE;
            newpos.y = FTOP+pos.y*SQSIZE;
            if ((kospos.x != newpos.x)||(kospos.y != newpos.y)) {
                if (kospos.x > newpos.x) {
                    kospos.x -= 2;     // Перемещение зайца на пиксель влево.
                    side = 3;       // Меняем картинку зайца
                } else if (kospos.x < newpos.x) {
                    kospos.x += 2;
                    side = 1;
                }
                if (kospos.y > newpos.y) {
                    kospos.y -= 2;
                    side = 2;
                } else if (kospos.y < newpos.y) {
                    kospos.y += 2;
                    side = 0;
                }
            } else {
                moving = false;
            }
            switch (state) {
                case ST_PLAYING:
                    Physics();
                    Render();
                    break;
                case ST_MENU:
                    RenderMenu();
                    break;
                case ST_EXIT:
                case ST_EXITING:
                    app->exit_status = true;
            }
			APP_ConsumeEv(ev_st, app);
			// Делаем что-нибудь
			//GDI_BeginPaint(&hDC, &hDisp, &hDraw);
			//GDI_FillRect(&hDC, 0, 0, 176, 220, ATI_565RGB(128, 160, 192));
			//GDI_EndPaint(&hDC, &hDisp, &hDraw);
			break;
	}

	return RESULT_OK;
}





// PM API: Exit - выход из приложения через диспетчер задач
UINT32	HandleExit(EVENT_STACK_T* ev_st,  APPLICATION_T* app) {

	dbg("HandleExit: Enter");

	APP_ConsumeEv(ev_st, app);
	app->exit_status = TRUE;

	dbg("HandleExit: Exit");

	return RESULT_OK;
}




// Функция обработки callback'а на дисплей
void	displayCbk(const RECT_T* updatedRect) {
	// Рисуем поверх UIS
}






UINT32  RenderSoftKeysAndHeader(BOOL lS, BOOL rS) {
	UINT32			length, offset, color;

	char 			szHeader[128], szLeftSoft[32], szRightSoft[32];

	if (state == ST_PLAYING) {
		sprintf(szHeader, "%s. LEVEL %i", "KOSILKA", level);
		sprintf(szLeftSoft, "%s", "MENU");
		sprintf(szRightSoft, "%s", "RESTART");
	}

	if (state == ST_MENU) {
		sprintf(szHeader, "%s", "MAIN MENU");
		sprintf(szLeftSoft, "%s", "EXIT");
		sprintf(szRightSoft, "%s", "SELECT");
	}

	if (GDI_BeginPaint(&hDC, &hDisp, &hDraw) == RESULT_OK) {
		// Рисуем заголовок
		GDI_FillRect(&hDC, 0, 0, DISPLAY_WIDTH, 16, clBackNormal);
		length = getStringWidth(szHeader, 1, 1, 0);
		offset = (DISPLAY_WIDTH - length)/2;
		drawString(hDC, offset, 4, szHeader, clNormal, clTrans, 1, 1, 0);

		// Рисуем левую софть
		if (lS) { color = clBackActive; } else { color = clBackNormal; }
		GDI_FillRect(&hDC, 0, DISPLAY_HEIGHT-16, DISPLAY_WIDTH/2, 16, color);
		if (lS) { color = clActive; } else { color = clNormal; }
		drawString(hDC, 4, DISPLAY_HEIGHT-12, szLeftSoft, color, clTrans, 1, 1, 0);

		// Рисуем правую софть
		length = getStringWidth(szRightSoft, 1, 1, 0);
		offset = DISPLAY_WIDTH - 5 - length;
		if (rS) { color = clBackActive; } else { color = clBackNormal; }
		GDI_FillRect(&hDC, DISPLAY_WIDTH/2, DISPLAY_HEIGHT-16, DISPLAY_WIDTH/2, 16, color);
		if (rS) { color = clActive; } else { color = clNormal; }
		drawString(hDC, offset, DISPLAY_HEIGHT-12, szRightSoft, color, clTrans, 1, 1, 0);

		// Не рисуем :)
		GDI_EndPaint(&hDC, &hDisp, &hDraw);
	}

	return RESULT_OK;
}






UINT32 RenderMenu() {
	UINT32	length, offset, color;
	INT8	i;
	char	buf[64];

	RenderSoftKeysAndHeader(keys.lsoft, keys.rsoft);

	if (GDI_BeginPaint(&hDC, &hDisp, &hDraw) == RESULT_OK) {
		GDI_FillRect(&hDC, 0, 16, DISPLAY_WIDTH, DISPLAY_HEIGHT-32, ATI_565RGB(0, 0, 0));

		for (i = 0; i <= 7; i++) {
			if (menusel == i) { color = clActive; } else { color = clNormal; }
			if (i > 4) { color = ATI_565RGB(136, 136, 204); }
			switch (i) {
				case 0:
					sprintf(buf, "%s", "CONTINUE");
					break;
				case 1:
					sprintf(buf, "%s", "NEXT LEVEL");
					break;
				case 2:
					sprintf(buf, "%s", "PREV LEVEL");
					break;
				case 3:
					sprintf(buf, "%s", "EXIT");
					break;
				case 4:
					sprintf(buf, "%s", "---------------");
					break;
				case 5:
					sprintf(buf, "%s", "© 2010 Cool-T & Motofan.Ru");
					break;
				case 6:
					sprintf(buf, "%s", "Special thanks to tim apple");
					break;
				case 7:
					sprintf(buf, "%s", "llldimedrolll and SpyHEX");
					break;
			}
			if (i != 4) {
				length = getStringWidth(buf, 1, 1, 0);
				offset = (DISPLAY_WIDTH - length)/2;
				drawString(hDC, offset, 42 + i*18, buf, color, clTrans, 1, 1, 0);
			}
		}

        GDI_EndPaint(&hDC, &hDisp, &hDraw);
	}

	return RESULT_OK;
}




void Render() {
    INT8	i, j, k;

	AHIPOINT_T	zpt = {0, 0};
	AHIRECT_T	zrc = {0, 0, 0, 0};

	RenderSoftKeysAndHeader(keys.lsoft, keys.rsoft);

	if (GDI_BeginPaint(&hDC, &hDisp, &hDraw) == RESULT_OK) {

		GDI_FillRect(&hDC, 0, 16, DISPLAY_WIDTH, DISPLAY_HEIGHT-32, ATI_565RGB(0, 0, 0));

        for (k = 0; k <= 2; k++) {
            GDI_CopyAniToTempSurf(&hDC, &tiles[k]);
            for (i = 0; i < SIZE; i++) {
                for (j = 0; j < SIZE; j++) {
                    if (k == LvlGetData(j, i)-1) {
                        GDI_DrawAniBitmap(&hDC, &hDraw, NULL, FLEFT+SQSIZE*j, FTOP+SQSIZE*i);
                    }
                }
            }
        }

        kos.frame = side;
        GDI_DrawAniBitmap(&hDC, &hDraw, &kos, kospos.x, kospos.y);

        GDI_EndPaint(&hDC, &hDisp, &hDraw);
    }
}





void	keyboardCbk(APPLICATION_T* app, KEY_DATA_T* key) {

	switch (state) {
		case ST_PLAYING:
            if (!key->state) {
                if (key->code & MULTIKEY_SOFT_LEFT) { state = ST_MENU; }
                if (key->code & MULTIKEY_SOFT_RIGHT) { NewGame(level); }
            }
			break;
        //case ST_GAMEOVER:
        //case ST_COMPLETED:
		case ST_MENU:
            if (!key->state) {
                if ((key->code & MULTIKEY_SOFT_RIGHT)||(key->code & MULTIKEY_JOY_OK)||(key->code & MULTIKEY_5)) { Menu_SelectItem(); break; }
                if (key->code & MULTIKEY_SOFT_LEFT) { Menu_BackItem(); break; }
            } else {
                if ((key->code & MULTIKEY_UP)||(key->code & MULTIKEY_2)) { Menu_PrevItem(); break; }
                if ((key->code & MULTIKEY_DOWN)||(key->code & MULTIKEY_8)) { Menu_NextItem(); break; }
            }
			break;
		case ST_GAMEOVER:
			if (key != NULL) { state = ST_MENU; }
			break;
	}

	if ((key->state)&&((key->code & MULTIKEY_2)||(key->code & MULTIKEY_UP))) {
		keys.up = true;
	} else {
		keys.up = false;
	}

	if ((key->state)&&((key->code & MULTIKEY_4)||(key->code & MULTIKEY_LEFT))) {
		keys.left = true;
	} else {
		keys.left = false;
	}

	if ((key->state)&&((key->code & MULTIKEY_6)||(key->code & MULTIKEY_RIGHT))) {
		keys.right = true;
	} else {
		keys.right = false;
	}

	if ((key->state)&&((key->code & MULTIKEY_8)||(key->code & MULTIKEY_DOWN))) {
		keys.down = true;
	} else {
		keys.down = false;
	}

	if ((key->state)&&((key->code & MULTIKEY_5)||(key->code & MULTIKEY_JOY_OK))) {
		keys.fire = true;
	} else {
		keys.fire = false;
	}

	if ((key->state)&&(key->code & MULTIKEY_SOFT_LEFT)) {
		keys.lsoft = true;
	} else {
		keys.lsoft = false;
	}

	if ((key->state)&&(key->code & MULTIKEY_SOFT_RIGHT)) {
		keys.rsoft = true;
	} else {
		keys.rsoft = false;
	}
}






BOOL Lose() {
    BOOL    ret = false;
    BOOL    check = false;
    UINT8   up = LvlGetData(pos.x, pos.y-1), down = LvlGetData(pos.x, pos.y+1);
    UINT8   left = LvlGetData(pos.x-1, pos.y), right = LvlGetData(pos.x+1, pos.y);

    if ((pos.x <= 0)&&(right != g)&&(up != g)&&(down != g)) {
        ret = true;
        check = true;
    }

    if ((pos.x >= lvl.width-1)&&(left != g)&&(up != g)&&(down != g)) {
        ret = true;
        check = true;
    }

    if ((pos.y <= 0)&&(right != g)&&(left != g)&&(down != g)) {
        ret = true;
        check = true;
    }

    if ((pos.y >= lvl.height-1)&&(right != g)&&(left != g)&&(up != g)) {
        ret = true;
        check = true;
    }

    if ((!check)&&(right != g)&&(left != g)&&(down != g)&&(up != g)) {
        ret = true;
    }

    return ret;
}




BOOL Won() {
    INT8 i, j;
    BOOL    ret = true;

    for (i = 0; i < lvl.height; i++) {
        for (j = 0; j < lvl.width; j++) {
            if (LvlGetData(j, i) == g) {
                ret = false;
            }
        }
    }
    return ret;
}





BOOL Mov(INT8 X, INT8 Y) {
    BOOL    ret = true;

    if ((LvlGetData(X, Y) == g)&&(X >= 0)&&(X < lvl.width)&&(Y >= 0)&&(Y < lvl.height)) {
        //field[X][Y] = c;
        pos.x = X;
        pos.y = Y;
    } else {
        ret = false;
    }

    return ret;
}




void NewGame(INT8 nLevel) {
	WCHAR			u_lvl_url[MAX_SZ_SIZE+1];
	char			lvl_name[MAX_SZ_SIZE+1];
	WCHAR			u_lvl_name[MAX_SZ_SIZE+1];

	FILE_HANDLE_T	lvlfile;
	UINT32			readen;

    INT8 i, j;

    state = ST_INACTIVE;

    if (lvl.data != NULL) {
		mfree(lvl.data);
		lvl.data = NULL;
	}

	sprintf(lvl_name, "/Kosilka.res/levels/level%i.dat", nLevel);
	w_atow(lvl_name, u_lvl_name, MAX_SZ_SIZE);
    w_mkpath(u_lvl_url, workdir, u_lvl_name, true);

	lvlfile = DL_FsOpenFile(u_lvl_url, FILE_READ_MODE, 0);
	if (lvlfile != FILE_HANDLE_INVALID) {
	    DL_FsReadFile(&lvl.width, sizeof(INT32), 1, lvlfile, &readen);
	    lvl.width = E32(lvl.width);
	    DL_FsReadFile(&lvl.height, sizeof(INT32), 1, lvlfile, &readen);
	    lvl.height = E32(lvl.height);
        lvl.data = malloc((UINT32)(lvl.width*lvl.height));
		DL_FsReadFile(lvl.data, sizeof(INT8), 100, lvlfile, &readen);
		DL_FsCloseFile(lvlfile);
	} else {
	    lvl.width = 10;
	    lvl.height = 10;
		for (i = 0; i < lvl.height; i++) {
			for (j = 0; j < lvl.width; j++) {
                LvlSetData(j, i, g);
			}
		}
	}

    pos.x = 0;
    pos.y = 0;
    kospos.x = FLEFT+pos.x*SQSIZE;
    kospos.y = FTOP+pos.y*SQSIZE;

	state = ST_PLAYING;

    Mov(pos.x, pos.y);
}






void Physics() {
    AHIPOINT_T      pt = { kospos.x, kospos.y };

    if ((keys.left)&&(!moving)) {
        moving = true;
        side = 3;
        Mov(pos.x-1, pos.y);
    }
    if ((keys.right)&&(!moving)) {
        moving = true;
        side = 1;
        Mov(pos.x+1, pos.y);
    }
    if ((keys.up)&&(!moving)) {
        moving = true;
        side = 2;
        Mov(pos.x, pos.y-1);
    }
    if ((keys.down)&&(!moving)) {
        moving = true;
        side = 0;
        Mov(pos.x, pos.y+1);
    }

    if (((pos.x*SQSIZE + FLEFT) == kospos.x)&&((pos.y*SQSIZE + FTOP) == kospos.y)) {
        if (LvlGetData(pos.x, pos.y) == g) {
            LvlSetData(pos.x, pos.y, c);
        }

        if (Won()) {
            level++;
            if (level > lastlevel) {
                lastlevel = level;
            }
            NewGame(level);
        } else {
            if (Lose()) {
                NewGame(level);
            }
        }
    }


}





UINT8	LvlGetData(INT32 dwX, INT32 dwY) {
	UINT8		data = NULL;
	UINT32		offset = (UINT32)(lvl.width*dwY + dwX);

	if (offset <= (UINT32)(lvl.width*lvl.height)) {
		data = *(UINT8*)(lvl.data + offset);
	}

	return data;
}





UINT8	LvlSetData(INT32 dwX, INT32 dwY, UINT8 data) {
	UINT8*		dest;
	UINT32		offset = (UINT32)(lvl.width*dwY + dwX);

	if (offset <= (UINT32)(lvl.width*lvl.height)) {
		dest = (UINT8*)(lvl.data + offset);
		*dest = data;
	}

	return data;
}






void	Menu_PrevItem(void) {
	switch (state) {
		case ST_MENU:
			if (menusel > 0) { menusel--; } else { menusel = 3; }
			break;
	}
}









void	Menu_NextItem(void) {
	switch (state) {
		case ST_MENU:
			if (menusel < 3) { menusel++; } else { menusel = 0; }
			break;
	}
}









void	Menu_BackItem(void) {
	switch (state) {
		case ST_MENU:
			state = ST_EXITING;
			break;
	}
}







void	Menu_SelectItem(void) {
	UINT32		i;

	switch (state) {
		case ST_MENU:
			switch (menusel) {
				case 0:
                    state = ST_PLAYING;
                    break;
                case 1:
                    if ((level < lastlevel)) { level++; }
                    NewGame(level);
                    break;
                case 2:
                    if (level > 1) { level--; }
                    NewGame(level);
                    break;
                case 3:
                    state = ST_EXIT;
                    break;
			}
			break;
	}

	menusel = 0;
}



// Конец файла. GAME OVER!
